package com.cyf.activemq.service.impl;

import com.cyf.activemq.network.bean.*;
import com.cyf.activemq.network.bean.person.MqSendStatisticalDataReq;
import com.cyf.activemq.service.MqService;
import com.cyf.activemq.service.SendMsgService;
import com.cyf.app.service.AppPushService;
import com.cyf.service.bean.CustomException;
import com.cyf.app.service.JpushMessageService;
import com.cyf.db.bean.*;
import com.cyf.db.mapper.*;
import com.cyf.redis.RedisService;
import com.cyf.smartCity.bean.*;
import com.cyf.util.BasicProperties;
import com.cyf.util.DateUtil;
import com.cyf.util.ObjectMapperUtils;
import com.cyf.util.ParkingUtil;
import com.cyf.wechat.service.WechatSendService;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.io.IOException;
import java.text.DecimalFormat;
import java.text.SimpleDateFormat;
import java.util.*;

/**
 * activemq接口实现类：处理：入场通知，出场通知，人管平台的定时发送统计信息等
 * Created by cage on 2017/3/18.
 */
@Service
public class MqServiceImpl implements MqService {

    private static final Logger logger = LoggerFactory.getLogger(MqServiceImpl.class);
    private static final DecimalFormat decimalFormat = new DecimalFormat("0.00");

    @Autowired
    private AppUserCarMapper appUserCarMapper;
    @Autowired
    private JpushMessageService jpushMessageService;
    @Autowired
    private AppCarMapper appCarMapper;
    @Autowired
    private UserMapper userMapper;

    @Autowired
    private BasicProperties basicProperties;
    @Autowired
    private SendMsgService sendMsgService;
    @Autowired
    private RedisService redisService;
    @Autowired
    private AppPushService appPushService;
    @Autowired
    private WechatSendService wechatSendService;
    @Autowired
    private UsersWechatMapper usersWechatMapper;


    @Override
    public void sendStatisticalDataForPerson(MqSendStatisticalDataReq mqSendStatisticalDataReq) {
        List<User> userList = userMapper.getNeedSendStatisDataUsers();
        if (userList == null || userList.size() == 0) {
            logger.debug("不给任何人发送人管平台统计信息");
            return;
        }
        for (User user : userList) {
            // 21-99本地测试专门车场
            String openid = usersWechatMapper.getOpenidByUserIdAndApiUserId(user.getId(), 21);
            if (!StringUtils.isEmpty(openid)) {
                try {
                    String depts = ObjectMapperUtils.getObjectMapper().writeValueAsString(mqSendStatisticalDataReq.getDepts());
                    wechatSendService.sendStatisticalData(openid, depts, mqSendStatisticalDataReq.getEmployeeInNum(), mqSendStatisticalDataReq.getEmployeeOutNum(), mqSendStatisticalDataReq.getTime());
                } catch (JsonProcessingException e) {
                    logger.error("object转JSON异常，不向微信用户({})发送人管平台统计信息！", openid);
                }
            }
        }
    }

    @Override
    public void sendCarInInfoForPmsvr(MqCarInReq mqCarInReq) {
        // 向app端、微信端发送通知消息
        AppCar appCar = appCarMapper.getByPlate(mqCarInReq.getPlate());
        if (appCar != null) {
            List<User> userList = appUserCarMapper.getUserByCarId(appCar.getId());
            if (userList != null && userList.size() > 0) {
                Date inTime = DateUtil.convertSeconds2Date(mqCarInReq.getInTime());
                String inTimeStr = DateUtil.formatDate(inTime, "yyyy-MM-dd HH:mm:ss");
                for (User user : userList) {
                    List<UsersWechat> usersWechatList = usersWechatMapper.listByUserId(user.getId());
                    for (UsersWechat usersWechat : usersWechatList) {
                        if (usersWechat != null && !StringUtils.isEmpty(usersWechat.getOpenid())) {
                            wechatSendService.carIn(usersWechat.getApiUserId(), usersWechat.getOpenid(), mqCarInReq.getPlate(), mqCarInReq.getParkingName(), inTimeStr);
                        } else {
                            logger.debug("{}未注册微信公众号！", user.getMobile());
                        }
                    }

                    // TODO: 2017/5/24 app版本用户均升级到2.0.4版本后，使用上面的代码。appPushService ,
                    // TODO: 2020-06-22 App 暂时不在使用将极光推送注释掉
//                    if (!StringUtils.isEmpty(user.getToken())) {
//                        String alias = user.getMobile();
//                        Map<String, String> extras = new HashMap<>();
//                        extras.put("plate", mqCarInReq.getPlate());
//                        extras.put("parkingName", mqCarInReq.getParkingName());
//                        extras.put("inTime", inTimeStr);
//                        extras.put("noticeType", "1");
//                        extras.put("outTime", "");
//                        extras.put("fee", "0");
//                        extras.put("stayTime", "");
//                        extras.put("stayTime", "");
//                        String content = "车辆" + mqCarInReq.getPlate() + "在" + ParkingUtil.getParkingName(mqCarInReq.getParkingName()) + "入场";
//                        logger.info("通知app用户车辆入场:{}", content);
//                        jpushMessageService.sendPushByAlias(alias, content, extras);
//                    } else {
//                        logger.debug("{}未注册app！", user.getMobile());
//                    }
                }
            }
        }
    }

    @Override
    public void sendCarOutInfoForPmsvr(MqCarOutReq mqCarOutReq) {

        // 准备数据：为 app和微信端 通知
        String stayTime = "未知";
        if (mqCarOutReq.getStayTime() != null) {
            stayTime = DateUtil.formatTime((long) (mqCarOutReq.getStayTime()));
        }
        String outTime = "未知";
        if (mqCarOutReq.getOutTime() != null && mqCarOutReq.getOutTime() != 0) {
            outTime = DateUtil.formatDate(DateUtil.convertSeconds2Date(mqCarOutReq.getOutTime()), "yyyy-MM-dd HH:mm:ss");
        }
        String inTime = "未知";
        if (mqCarOutReq.getInTime() != null && mqCarOutReq.getInTime() != 0) {
            inTime = DateUtil.formatDate(DateUtil.convertSeconds2Date(mqCarOutReq.getInTime()), "yyyy-MM-dd HH:mm:ss");
        }

        // 向app端发送通知消息
        AppCar appCar = appCarMapper.getByPlate(mqCarOutReq.getPlate());
        if (appCar != null) {
            List<User> userss = appUserCarMapper.getUserByCarId(appCar.getId());
            if (userss != null && userss.size() > 0) {
                for (User user : userss) {
                    List<UsersWechat> usersWechatList = usersWechatMapper.listByUserId(user.getId());
                    for (UsersWechat usersWechat : usersWechatList) {
                        if (usersWechat != null && !StringUtils.isEmpty(usersWechat.getOpenid())) {
                            // 6. 通知微信用户
                            logger.info("通知微信用户车辆（{}）出场!", mqCarOutReq.getPlate());
                            wechatSendService.carOut(usersWechat.getApiUserId(), usersWechat.getOpenid(), mqCarOutReq.getPlate(), mqCarOutReq.getParkingName(), stayTime, outTime, mqCarOutReq.getFee());
                        } else {
                            logger.debug("{}未注册微信公众号！", user.getMobile());
                        }
                    }

//                    if (!StringUtils.isEmpty(user.getToken())) {
////                    appPushService.pushCarOutNotification(appUser.getMobile(), mqCarOutReq.getPlate(), mqCarOutReq.getParkingName());
//                        // TODO: 2017/5/24 app版本用户均升级到2.0.4版本后，使用上面的代码。appPushService
//                        // TODO:2020-06-22 app 不在使用将极光推送干掉不在使用
//                        String alias = user.getMobile();
//                        Map<String, String> extras = new HashMap<>();
//                        extras.put("plate", mqCarOutReq.getPlate());
//                        extras.put("parkingName", mqCarOutReq.getParkingName());
//                        extras.put("outTime", outTime);
//                        if (mqCarOutReq.getFee() != null) {
//                            extras.put("fee", decimalFormat.format(mqCarOutReq.getFee() * 0.01));
//                        } else {
//                            extras.put("fee", decimalFormat.format(0 * 0.01));
//                        }
//                        extras.put("stayTime", stayTime);
//                        extras.put("noticeType", "2");
//                        extras.put("inTime", inTime);
//                        String content = "车辆" + mqCarOutReq.getPlate() + "从" + ParkingUtil.getParkingName(mqCarOutReq.getParkingName()) + "出场";
//                        logger.info("通知app用户车辆出场:{}", content);
//                        jpushMessageService.sendPushByAlias(alias, content, extras);
//                    } else {
//                        logger.debug("{}未注册app！", user.getMobile());
//                    }
                }
            }
        }
    }

    @Override
    public synchronized void sendExpiredWarningMsg(MqExpiredWarningReq mqExpiredWarningReq) {
        // 查询该车辆是否是微信用户注册的车辆
        List<AppUserCar> appUserCarList = appUserCarMapper.getByPlate(mqExpiredWarningReq.getPlate());
        if (appUserCarList != null && appUserCarList.size() > 0) {
            for (AppUserCar appUserCar : appUserCarList) {

                List<UsersWechat> usersWechatList = usersWechatMapper.listByUserId(appUserCar.getUserid());

                for (UsersWechat usersWechat : usersWechatList) {
                    if (usersWechat != null && !StringUtils.isEmpty(usersWechat.getOpenid())) {
                        if (appUserCar.getSendMsg() != 1) {
                            // 6. 通知微信用户
                            logger.info("通知微信用户车辆（{}）即将过期!", mqExpiredWarningReq.getPlate());
                            boolean result = wechatSendService.sendExpiredWarning(usersWechat.getApiUserId(), usersWechat.getOpenid(), mqExpiredWarningReq.getPlate(),
                                    ParkingUtil.getParkingName(mqExpiredWarningReq.getParkingName()),
                                    mqExpiredWarningReq.getEndTime(),
                                    appUserCar.getUserid() + "");
                            if (result) {
                                logger.info("微信用户当天已经发送月卡过期消息,更新发送状态");
                                appUserCarMapper.updateSendMsgById(appUserCar.getId());
                            } else {
                                logger.warn("用户({}){}发送({})过期消息失败");
                            }
                        } else {
                            logger.info("用户({}){}已经发送过({})过期消息", appUserCar.getUserid(), new Date(), mqExpiredWarningReq.getPlate());
                        }
                    }
                }
            }

        }

    }

    @Override
    public MqCarLockOrNoRsp carLockOrNo(String plate, Integer parkingId, Integer lockStatus) throws CustomException {
        String uuid = UUID.randomUUID().toString();
        MqCarLockOrNoReq mqCarLockOrNoReq = new MqCarLockOrNoReq();
        mqCarLockOrNoReq.setOptid(MqBusinessOpt.CARLOCKORNO);
        mqCarLockOrNoReq.setParkingId(parkingId);
        mqCarLockOrNoReq.setUuid(uuid);
        mqCarLockOrNoReq.setPlate(plate);
        mqCarLockOrNoReq.setStatus(lockStatus);
        try {
            sendMsgService.sendQueueMessageText(ObjectMapperUtils.getObjectMapper().writeValueAsString(mqCarLockOrNoReq));
        } catch (JsonProcessingException e) {
            throw new CustomException("操作失败！");
        }
        Object result = redisService.getWithExpireTime(uuid, basicProperties.getAppNetworkTimeOut());
        if (result == null) {
            logger.info("消息队列中获取消息失败！");
            throw new CustomException("网络超时！");
        }
        MqCarLockOrNoRsp mqCarLockOrNoRsp = (MqCarLockOrNoRsp) result;
        if (mqCarLockOrNoRsp.getResult() == MqBusinessRsp.ERROR) {
            logger.info("app用户锁定或解锁车辆失败：{}", mqCarLockOrNoRsp.getStrError());
            throw new CustomException("操作失败！");
        }
        return mqCarLockOrNoRsp;
    }

    @Override
    public MqGetFeeRsp getFee(String plate, Integer parkingId, Date outTime) throws CustomException {

        // 获取费用
        String uuid = UUID.randomUUID().toString();
        SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm");
        String outTimeStr = format.format(outTime);
        MqGetFeeReq mqGetFeeReq = new MqGetFeeReq();
        mqGetFeeReq.setOptid(MqBusinessOpt.GETFEE);
        mqGetFeeReq.setUuid(uuid);
        mqGetFeeReq.setParkingId(parkingId);
        mqGetFeeReq.setPlate(plate);
        mqGetFeeReq.setOutTime(outTimeStr);
        try {
            sendMsgService.sendQueueMessageText(ObjectMapperUtils.getObjectMapper().writeValueAsString(mqGetFeeReq));
        } catch (JsonProcessingException e) {
            throw new CustomException("获取停车费失败！");
        }
        Object result = redisService.getWithExpireTime(uuid, basicProperties.getAppNetworkTimeOut());
        if (result == null) {
            logger.info("消息队列中获取消息失败！");
            throw new CustomException("网络超时！");
        }
        ObjectMapper objectMapper = ObjectMapperUtils.getObjectMapper();
        try {
            String resultStr = objectMapper.writeValueAsString(result);
//            logger.info("{}" , resultStr);
            MqGetFeeRsp mqGetFeeRsp = objectMapper.readValue(resultStr, MqGetFeeRsp.class);
            if (mqGetFeeRsp.getResult() == MqBusinessRsp.ERROR) {
                logger.info("app用户获取停车费失败：{}", mqGetFeeRsp.getStrError());
                throw new CustomException("获取停车费失败！");
            }
            return mqGetFeeRsp;
        } catch (IOException e) {
            logger.error("获取优惠券异常：{}", e);
            throw new CustomException("获取停车费失败！");
        }
    }

    @Override
    public MqGetFeeDescRsp getFeeDesc(int parkingId, int inParkingId) throws CustomException {

        // 获取费用
        String uuid = UUID.randomUUID().toString();
        MqGetFeeDescReq mqGetFeeDescReq = new MqGetFeeDescReq();
        mqGetFeeDescReq.setOptid(MqBusinessOpt.GETFEEDESC);
        mqGetFeeDescReq.setUuid(uuid);
        mqGetFeeDescReq.setParkingId(parkingId);
        mqGetFeeDescReq.setInParkingId(inParkingId);
        try {
            sendMsgService.sendQueueMessageText(ObjectMapperUtils.getObjectMapper().writeValueAsString(mqGetFeeDescReq));
        } catch (JsonProcessingException e) {
            throw new CustomException("获取费用信息失败！");
        }
        Object result = redisService.getWithExpireTime(uuid, basicProperties.getAppNetworkTimeOut());
        if (result == null) {
            logger.info("消息队列中获取消息失败！");
            throw new CustomException("网络超时！");
        }
        MqGetFeeDescRsp mqGetFeeDescRsp = (MqGetFeeDescRsp) result;
        if (mqGetFeeDescRsp.getResult() == MqBusinessRsp.ERROR) {
            logger.info("获取费用信息失败：{}", mqGetFeeDescRsp.getStrError());
            throw new CustomException("获取费用信息失败！");
        }
        return mqGetFeeDescRsp;
    }

    @Override
    public MqGetFeeRateRsp getFeeRate(Integer parkingId, ArrayList<String> plates) throws CustomException {
        String uuid = UUID.randomUUID().toString();
        MqGetFeeRateReq mqGetFeeRateReq = new MqGetFeeRateReq();
        mqGetFeeRateReq.setUuid(uuid);
        mqGetFeeRateReq.setOptid(MqBusinessOpt.GETFEERATE);
        mqGetFeeRateReq.setParkingId(parkingId);
        mqGetFeeRateReq.setPlates(plates);
        try {
            sendMsgService.sendQueueMessageText(ObjectMapperUtils.getObjectMapper().writeValueAsString(mqGetFeeRateReq));
        } catch (JsonProcessingException e) {
            throw new CustomException("获取费率失败！");
        }

        Object result = redisService.getWithExpireTime(uuid, basicProperties.getAppNetworkTimeOut());
        if (result == null) {
            logger.info("消息队列中获取消息失败！");
            throw new CustomException("网络超时！");
        }
        MqGetFeeRateRsp mqGetFeeRateRsp = (MqGetFeeRateRsp) result;
        if (mqGetFeeRateRsp.getResult() == MqBusinessRsp.ERROR) {
            logger.info("获取费率信息失败：{}", mqGetFeeRateRsp.getStrError());
            throw new CustomException("获取费用信息失败！");
        }
        return mqGetFeeRateRsp;
    }

    @Override
    public MqRegPersonAndCarRsp regPersonAndCar(MqRegPersonAndCarReq req) throws CustomException {
        String uuid = UUID.randomUUID().toString();
        req.setUuid(uuid);
        req.setOptid(MqBusinessOpt.TOC_REG_PERSON_AND_CAR);
        if (!sendMsgService.send(req)) {
            throw new CustomException("注册会员失败！");
        }

        Object result = redisService.getWithExpireTime(uuid, basicProperties.getAppNetworkTimeOut());
        if (result == null) {
            logger.info("消息队列中获取消息失败！");
            throw new CustomException("网络超时！");
        }
        MqRegPersonAndCarRsp rsp = (MqRegPersonAndCarRsp) result;
        if (rsp.getResult() == MqBusinessRsp.ERROR) {
            logger.info("获取费率信息失败：{}", rsp.getStrError());
            throw new CustomException(rsp.getStrError());
        }
        return rsp;
    }

    @Override
    public MqUpdatePersonAndCarRsp updatePersonAndCar(MqUpdatePersonAndCarReq req) throws CustomException {
        String uuid = UUID.randomUUID().toString();
        req.setUuid(uuid);
        req.setOptid(MqBusinessOpt.TOC_UPDATE_PERSON_AND_CAR);
        if (!sendMsgService.send(req)) {
            throw new CustomException("注册会员失败！");
        }

        Object result = redisService.getWithExpireTime(uuid, basicProperties.getAppNetworkTimeOut());
        if (result == null) {
            logger.info("消息队列中获取消息失败！");
            throw new CustomException("网络超时！");
        }
        MqUpdatePersonAndCarRsp rsp = (MqUpdatePersonAndCarRsp) result;
        if (rsp.getResult() == MqBusinessRsp.ERROR) {
            logger.info("获取费率信息失败：{}", rsp.getStrError());
            throw new CustomException(rsp.getStrError());
        }
        return rsp;
    }

    @Override
    public void sendPayOrder(PayOrder payOrder) {
        logger.info("向车场下发支付信息！");
        String uuid = UUID.randomUUID().toString();
        MqPayOrderReq mqPayOrderReq = new MqPayOrderReq();
        BeanUtils.copyProperties(payOrder, mqPayOrderReq);
        mqPayOrderReq.setOptid(MqBusinessOpt.PAYORDER);
        mqPayOrderReq.setUuid(uuid);
        mqPayOrderReq.setCreatedTime(DateUtil.convertDate2Seconds(payOrder.getCreatedTime()));
        mqPayOrderReq.setOutTime(DateUtil.convertDate2Seconds(payOrder.getOutTime()));
        mqPayOrderReq.setPayTime(DateUtil.convertDate2Seconds(payOrder.getPayTime()));
        mqPayOrderReq.setFeeEndTime(DateUtil.convertDate2Seconds(payOrder.getFeeEndTime()));
        mqPayOrderReq.setPayOrderId(payOrder.getId());
        try {
            sendMsgService.sendQueueMessageTextPay(ObjectMapperUtils.getObjectMapper().writeValueAsString(mqPayOrderReq));
        } catch (JsonProcessingException e) {
            logger.error("转换对象至json异常：{}", e);
        }
    }

    @Override
    public MqAddUpdatePersonAndCarRsp addUpdatePersonAndCar(MqAddUpdatePersonAndCarReq mqReq) throws CustomException {
        // 获取费用
        String uuid = UUID.randomUUID().toString();

        mqReq.setOptid(MqBusinessOpt.ADD_UPDATE_PERSON_AND_CAR);
        mqReq.setUuid(uuid);
        try {
            sendMsgService.sendQueueMessageText(ObjectMapperUtils.getObjectMapper().writeValueAsString(mqReq));
        } catch (JsonProcessingException e) {
            throw new CustomException("操作失败！");
        }
        Object result = redisService.getWithExpireTime(uuid, basicProperties.getAppNetworkTimeOut());
        if (result == null) {
            logger.info("【注册更新会员】消息队列中获取消息失败！key:{}", uuid);
            throw new CustomException("网络超时！");
        }
        MqAddUpdatePersonAndCarRsp mqRsp = (MqAddUpdatePersonAndCarRsp) result;
        if (mqRsp.getResult() == MqBusinessRsp.ERROR) {
            logger.info("{}", mqRsp.getStrError());
            throw new CustomException(mqRsp.getStrError());
        }
        return mqRsp;
    }

    @Override
    public MqOpenBarrierRsp openBarrier(String plate, int parkingId, int deviceId, int feeRspId) throws CustomException {
        // 获取费用
        String uuid = UUID.randomUUID().toString();
        MqOpenBarrierReq mqOpenBarrierReq = new MqOpenBarrierReq();
        mqOpenBarrierReq.setOptid(MqBusinessOpt.OPEN_BARRIER);
        mqOpenBarrierReq.setUuid(uuid);
        mqOpenBarrierReq.setParkingId(parkingId);
        mqOpenBarrierReq.setPlate(plate);
        mqOpenBarrierReq.setDeviceId(deviceId);
        mqOpenBarrierReq.setFeeRspId(feeRspId);
        try {
            sendMsgService.sendQueueMessageText(ObjectMapperUtils.getObjectMapper().writeValueAsString(mqOpenBarrierReq));
        } catch (JsonProcessingException e) {
            throw new CustomException("开闸失败！");
        }
        Object result = redisService.getWithExpireTime(uuid, basicProperties.getAppNetworkTimeOut());
        if (result == null) {
            logger.info("【开闸】 消息队列中获取消息失败！key:{}", uuid);
            throw new CustomException("网络超时！");
        }
        MqOpenBarrierRsp mqOpenBarrierRsp = (MqOpenBarrierRsp) result;
        if (mqOpenBarrierRsp.getResult() == MqBusinessRsp.ERROR) {
            logger.info("{}", mqOpenBarrierRsp.getStrError());
            throw new CustomException(mqOpenBarrierRsp.getStrError());
        }
        return mqOpenBarrierRsp;
    }

    @Override
    public MqCloseBarrierRsp closeBarrier(int parkingId, int deviceId) throws CustomException {
        String uuid = UUID.randomUUID().toString();
        MqCloseBarrierReq mqCloseBarrierReq = new MqCloseBarrierReq();
        mqCloseBarrierReq.setOptid(MqBusinessOpt.CLOSE_BARRIER);
        mqCloseBarrierReq.setParkingId(parkingId);
        mqCloseBarrierReq.setDeviceId(deviceId);
        mqCloseBarrierReq.setUuid(uuid);
        try {
            sendMsgService.sendQueueMessageText(ObjectMapperUtils.getObjectMapper().writeValueAsString(mqCloseBarrierReq));
        } catch (JsonProcessingException e) {
            throw new CustomException("关闸失败!");
        }
        Object result = redisService.getWithExpireTime(uuid, basicProperties.getAppNetworkTimeOut());
        if (result == null) {
            logger.info("【关闸】消息队列中获取消息失败！key:{}", uuid);
            throw new CustomException("网络超时！");
        }
        MqCloseBarrierRsp mqCloseBarrierRsp = (MqCloseBarrierRsp) result;
        if (mqCloseBarrierRsp.getResult() == MqBusinessRsp.ERROR) {
            logger.info("{}", mqCloseBarrierRsp.getStrError());
            throw new CustomException(mqCloseBarrierRsp.getStrError());
        }
        return mqCloseBarrierRsp;
    }
}
